
struct Fibonacci {
    curr: u32,
    next: u32
}

impl Iterator for Fibonacci {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let new_next = self.curr + self.next;
        self.curr = self.next;
        self.next = new_next;

        Some(self.curr)
    }
}
fn fibonacci() -> Fibonacci {
    Fibonacci { curr: 0, next: 1}
}

fn base(){
    let mut sequence = 0..3;

    println!("Four consecutive 'next' calls on 0..3");
    println!("> {:?}", sequence.next());
    println!("> {:?}", sequence.next());
    println!("> {:?}", sequence.next());
    println!("> {:?}", sequence.next());

    println!("Iterate through 0..3 using 'for'");
    for i in 0..3 {
        println!("> {}", i);
    }

    println!("The first four terms of the Fibonacci sequence are: ");
    for i in fibonacci().take(4) {
        println!("> {}", i);
    }

    println!("The next four terms of the Fibonacci sequence are: ");
    for i in fibonacci().skip(4).take(4) {
        println!("> {}", i);
    }

    let array = [1u32, 3, 3, 7];
    
    println!("Iterate the following array {:?}", &array);
    for i in array.iter() {
        println!("> {}", i);
    }

    for i in array {
        println!(">>> for loop: into: {i}");
    }

    {
        let array = [1; 0];
        println!("{:?}..all: x > 1: {}", array, array.iter().all(|&x| x>1));
        println!("{:?}..any: x > 1: {}", array, array.iter().any(|&x| x>1));
    }
    {
        let array = [1; 0];
        println!("{:?}.skip(1).all(): x > 1: {}", array, array.iter().skip(1).all(|&x| x>1));
        println!("{:?}.skip(1).any: x > 1: {}", array, array.iter().skip(1).any(|&x| x>1));
    }
    {
        let array = [1; 3];
        println!("{:?}.skip(3).all: x > 1: {}", array, array.iter().skip(3).all(|&x| x>1));
        println!("{:?}.skip(3).any: x > 1: {}", array, array.iter().skip(3).any(|&x| x>1));
    }
    {
        let array = [1; 3];
        println!("{:?}.skip(5).all: x > 1: {}", array, array.iter().skip(5).all(|&x| x>1));
        println!("{:?}.skip(5).any: x > 1: {}", array, array.iter().skip(5).any(|&x| x>1));
    }
    {
        let array = [1; 3];
        println!("{:?}.take(2).all: x > 1: {}", array, array.iter().take(2).all(|&x| x>0));

        //println!("{:?}.take(2).any: x > 1: {}", array, array.iter().take(2).any(|&x| x>1));
    }
}


//for-loop
//  suger for using into_iter
//  ????   collections will moved to into_iter functions;
//  does use the collections instant after for loop ????
//
//Iterator Categories: 
//  1. iter()  over &T 
//  2. iter_mut() over &mut T
//  3. into_iter() over T
//

fn for_loop(){
    {
        let values = vec![1, 2, 3, 4, 5];

        for x in values {
            println!("{x}");
        }
        //Compile error: values is moved into (vec.into_iter(self)) function
        // println!("vec: {:?}", values);
    }
    
    //solution 1 : vec.iter(&self), 
    {
        let values = vec![1, 2, 3, 4, 5];

        for x in values.iter() {
            println!("{x}");
        }
        
    //solution 2 : (&vec).into_iter()  ==> syntax OK 
        // impl into_iter for &Container
        for x in &values {
            println!("{x}");
        }
    }

    //solution 3: vec.iter_mut(&mut self)
    {
        let mut values = vec![1, 2, 3, 4, 5];
        for x in values.iter_mut() {
            println!("{x}");
        }
    }
}

// TODO: 
//adapters Categories:  
//  Consuming adapter 
//  Iterator adpaters
//
//Impl Iterator 
//  reimpl the next function for Trait std::iter::Iterator
//
fn use_adapters(){
    //todo!();
}



pub fn main(){
    base();
    for_loop();
    use_adapters();
}
